#!/bin/bash

#http://xstarcd.github.io/wiki/sysadmin/mongos_cluster.html
#http://www.ityouknow.com/mongodb/2017/08/05/mongodb-cluster-setup.html
#https://docs.mongodb.com/manual/reference/configuration-options/

set -e

# Script used to automate mongo cluster setup locally
#
# sirchen 2019.11.10

# 过滤日志
# tail -f mongos.log  | egrep -v 'Timer received error|audit|FlowEtcdWatcher|PeriodicTaskRunner|Cmd: NotSet'
# tail -f 3k1.log  | egrep -v 'sasl|serverStatus|ismaster|Successfully authenticated |remote client|cmongo|logout|isMaster|getMore:|Timer received error|audit|ping'
# tail -f 3k1.log  | egrep -v 'sasl|serverStatus|ismaster|Successfully authenticated |remote client|cmongo|logout|isMaster|getMore:|Timer received error|audit|ping|heartbeat|replSetUpdatePosition|replSetHeartbeat|hbmsg|Updating _lastCommittedOpTime|received notification that node|PeriodicTaskRunner|WTOplogJournalThread|NoopWriter|Setting replication|oldest_timestamp set|startPeriodicThreadToAbortExpiredTransactions|TTLMonitor'

if [ $# -lt 2 ]; then
    echo "$0 <cmd> <bin root absolute dir>"
    echo "You'd better choose a clean dir to execute the script, because there gonna many files generated within current working dir"
    echo "Command execution order:  start, config, addshard, stat"
    exit 1
fi

interval=1000

cmd=$1
BIN=$2
engine="wiredTiger"
host="9.134.5.74"
#host=`ip a | egrep -A 3 'eth[0-9]:|bond[0-9]:' | grep 'inet ' | grep -o '[0-9].*[/]' | awk -F / '{print $1}'`
#sed -i "s/HOST/$host/" conf/mongos*

if [ x$3 != x"" ]; then
    interval=$3
fi

if [ x$3 = x"rocksdb" ]; then
    engine=$3
fi

echo_with_color() {
    echo -e "\033[34m$1\033[0m"
}

# simple multiple mongod RS without config,mongos
start_debug() {
    printf -v nodes '%s ' node{1..11}
    rm -f 5k*

    dbpath=db-wt
    if [ $engine = "rocksdb" ]; then dbpath="db-rocks"; fi
    rm -rf $dbpath
    
    mkdir -p $dbpath
    cd $dbpath
    mkdir -p $nodes
    cd ..

    # $BIN/mongod --dbpath shard1/data-30001 --port 30001 --fork --logpath 3k1.log --replSet rs1

    # how to set one log component to 5, set others to 1
    echo_with_color "start 11 mongod (only 7 votes members)"
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node1 --port 50001 -vv --logpath 5k1.log &
    #$BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node1 --port 50000 --keyFile keyfile --logpath 50000.log
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node2 --port 50002 -vv --logpath 5k2.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node3 --port 50003 -v --logpath 5k3.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node4 --port 50004 --logpath 5k4.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node5 --port 50005 --logpath 5k5.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node6 --port 50006 --logpath 5k6.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node7 --port 50007 --logpath 5k7.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node8 --port 50008 --logpath 5k8.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node9 --port 50009 --logpath 5k9.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node10 --port 50010 --logpath 5k10.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node11 --port 50011 --logpath 5k11.log &

    sleep 5
    echo_with_color "rs.initiate "

    $BIN/mongo --port 50001 --eval "rs.initiate()"

    sleep 5

    echo_with_color "add 2nd node..."
    $BIN/mongo --port 50001 --eval "rs.add(\"localhost:50002\")"

    echo_with_color "add 3th arbiter node ..."
    $BIN/mongo --port 50001 --eval "rs.add(\"localhost:50003\", {arbiterOnly: true})"

    echo_with_color "add 4th node with priority=0 (votes default 1) ..."
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50004\", priority: 0})"

    echo_with_color "add 5th node with votes=0 (non-voting member must have priority=0)..."
    # 如果priority 给非0, 则报错 : "errmsg" : "priority must be 0 when non-voting (votes:0)",
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50005\", votes: 0, priority: 0})"

    echo_with_color "add 6th node with hidden(priority must be 0) and votes=1..."
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50006\", hidden: true, priority: 0})"

    # when votes=0, cannot ack write majority
    echo_with_color "add 7th node with hidden and votes=0..."
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50007\", hidden: true, votes: 0, priority: 0})"

    echo_with_color "add 8th node with Delayed RS member..."
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50008\", hidden: true, slaveDelay: 10, priority: 0})"

    echo_with_color "add 9th node (the last voting members)..."
    $BIN/mongo --port 50001 --eval "rs.add(\"localhost:50009\")"

    echo_with_color "add 10th node ..."
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50010\", votes: 0,  priority: 0})"

    echo_with_color "add 11th node... (cannot be joined)"
    $BIN/mongo --port 50001 --eval "rs.add({host: \"localhost:50011\"})"

    # to prevent from failover
    #$BIN/mongo --port 50001 --eval "cfg=rs.conf(); cfg.settings.heartbeatTimeoutSecs=3600; cfg.settings.electionTimeoutMillis=3600000; rs.reconfig(cfg)"
}

# start a 3 nodes cluster locally
start_simple() {
    printf -v nodes '%s ' node{1..3}
    rm -f 5k*

    dbpath=db-wt
    if [ $engine = "rocksdb" ]; then dbpath="db-rocks"; fi
    rm -rf $dbpath
    
    mkdir -p $dbpath
    cd $dbpath
    mkdir -p $nodes
    cd ..

    # how to set one log component to 5, set others to 1
    echo_with_color "start 3 mongod"
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node1 --port 50001 --logpath 5k1.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node2 --port 50002 --logpath 5k2.log &
    $BIN/mongod --replSet rs1 --storageEngine $engine  --dbpath ./$dbpath/node3 --port 50003 --logpath 5k3.log &

    sleep 5
    echo_with_color "rs.initiate "

    $BIN/mongo --port 50001 << eof 
    rs.initiate({ _id: "rs1", version: 1, members: [
        { _id:0, host: "localhost:50001" },
        { _id:1, host: "localhost:50002" },
        { _id:2, host: "localhost:50003","arbiterOnly" : true }
    ], 
    settings: { chainingAllowed: false}
    })
eof
    sleep 5
}

# 启动在 60000 端口的 RS
start_simple2() {
    printf -v nodes '%s ' node{4..6}
    rm -f 6k*

    dbpath=db-wt
    if [ $engine = "rocksdb" ]; then dbpath="db-rocks"; fi
    rm -rf $dbpath
    
    mkdir -p $dbpath
    cd $dbpath
    mkdir -p $nodes
    cd ..

    # how to set one log component to 5, set others to 1
    echo_with_color "start 3 mongod"
    $BIN/mongod --replSet rs2 --storageEngine $engine  --dbpath ./$dbpath/node4 --port 60001 --logpath 6k1.log &
    $BIN/mongod --replSet rs2 --storageEngine $engine  --dbpath ./$dbpath/node5 --port 60002 --logpath 6k2.log &
    $BIN/mongod --replSet rs2 --storageEngine $engine  --dbpath ./$dbpath/node6 --port 60003 --logpath 6k3.log &

    sleep 5
    echo_with_color "rs.initiate "

    $BIN/mongo --port 60001 << eof 
    rs.initiate({ _id: "rs2", version: 1, members: [
        { _id:0, host: "localhost:60001" },
        { _id:1, host: "localhost:60002" },
        { _id:2, host: "localhost:60003","arbiterOnly" : true }
    ], 
    settings: { chainingAllowed: false}
    })
eof
    sleep 5
}

create_user() {
    $BIN/mongo mongodb://admin:123456@$host:$1/admin << eof

    use admin
    db.createRole({ "role" : "restoreoplog", "privileges" : [ { "resource" : { "anyResource" : true }, "actions" : [ "anyAction" ] } ], "roles" : [ ] })
    // If admin has no restoreoplog role, db.getCollection("system.version").count()
    // will fail, reporting:
    //   not authorized on db1 to execute command { find: system.users ...
    // db.grantRolesToUser("admin", [ { "role": "restoreoplog", "db": "admin" }])

    db.createUser({user: "mongouser", pwd: "123456", "roles" : [ { "role" : "dbAdminAnyDatabase", "db" : "admin" }, { "role" : "readWriteAnyDatabase", "db" : "admin" }, { "role" : "backup", "db" : "admin" }, { "role" : "restore", "db" : "admin" }, { "role" : "clusterAdmin", "db" : "admin" }, { "role" : "restoreoplog", "db" : "admin" } ]})  

    // 集群创建时不应该创建 mongouser_noauth 用户,由master在开启免认证时建
    // 不过,若开启了免认证,一定得有这个用户
    db.createUser({user: "mongouser_noauth", pwd: "123456", "roles" : [ { "role" : "dbAdminAnyDatabase", "db" : "admin" }, { "role" : "readWriteAnyDatabase", "db" : "admin" }, { "role" : "backup", "db" : "admin" }, { "role" : "restore", "db" : "admin" }, { "role" : "clusterAdmin", "db" : "admin" }, { "role" : "restoreoplog", "db" : "admin" } ]})  

    db.createUser({user: "user1", pwd:"user1", roles: [ {role: "readWrite", db: "db1"} ] })

    use db1
    db.createUser({user: "user3", pwd:"user3", roles: [ {role: "read", db: "db1"} ] })

    use db1
    db.createUser({user: "user4", pwd:"user4", roles: [ {role: "read", db: "db2"} ] })

eof
    # 便于gdb 调试主节点(注意在重启时可以造成长时间未选到主)
    # 不适合放这里,mongos 不能用
    #$BIN/mongo mongodb://admin:123456@$host:$1/admin --eval "cfg=rs.conf(); cfg.settings.heartbeatTimeoutSecs=3600; cfg.settings.electionTimeoutMillis=3600000; rs.reconfig(cfg)"

}


write_data() {
    echo_with_color "writing sample data to (port=$1) and create users ..."
    $BIN/mongo mongodb://admin:123456@$host:$1/admin << eof
    // show current user and role
    db.runCommand({"connectionStatus":1})

    use config
    // make easier to split & move Chunks
    db.settings.save({_id:"chunksize", value:2})

    use db1
    for (var i=1; i<=10; i++) {
        db.t.insert({k: i, v: i+1, v2:[i+2,i+3]})
    }

    sh.enableSharding("db2")
    use db2
    for (var i=1; i<=10; i++) {
        db.t.insert({ k: i, v: i+1, v2:[i+2,i+3], v3: i+4})
    }
    db.t.createIndex({ v: 1} , { unique : true})

    // use mongoimport to import some data
    // mongoimport --host localhost --port 60001 --db covid --collection t1 --file us-counties.csv --type csv --headerline

    sh.shardCollection("db2.range_sharded", { k:1}, true)
    // numInitialChunks must be with hashed sharding, defaults 2 per shard
    // Hashed shard keys cannot be declared unique. It's possible to ensure uniqueness on the hashed field by declaring an additional (non-hashed) unique index on the field
    sh.shardCollection("db2.hashed_sharded", { k:"hashed"}, false, {numInitialChunks: 10})
eof

    create_user $1
}

__initialize_shard1() {
    echo_with_color "rs.initiate shard1"
    $BIN/mongo --port 30001 << eof
    config={_id:"shard1",members: [ { _id:0, host:"$host:30001" }, { _id:1, host:"$host:30002" },{ _id:2, host:"$host:30003" } ]}
    use admin
    rs.initiate(config)
eof

    while true; do
        primary1=`$BIN/mongo --host $host --port 30001 --eval "db.isMaster()" | grep primary | awk -F '"' '{print $4}'`
        if [ x$primary1 != x ]; then
            echo "shard1 primary=$primary1"
            break
        fi
        sleep 1
    done

    # must against primary
    echo_with_color "adding admin to shard1 against primary: $primary1"
    primary_port=${primary1#*:}

    # 如果 没有这个sleep , 出现 Error: couldn't add user: not master for 3.6
    sleep 3

    $BIN/mongo mongodb://localhost:${primary_port}/admin --eval 'db.createUser({ user: "admin", pwd: "123456", roles:[ { role: "root", db : "admin" }] })'
}

__initialize_shard2() {
    echo_with_color "rs.initiate shard2"
    $BIN/mongo --port 40001 << eof
    config={_id:"shard2",members: [ { _id:0, host:"$host:40001" }, { _id:1, host:"$host:40002" },{ _id:2, host:"$host:40003" } ]}
    use admin
    rs.initiate(config)
eof

    while true; do
        primary2=`$BIN/mongo --host $host --port 40001 --eval "db.isMaster()" | grep primary | awk -F '"' '{print $4}'`
        if [ x$primary2 != x ]; then
            echo "shard2 primary=$primary2"
            break
        fi
        sleep 1
    done

    echo_with_color "adding admin to shard2 against primary: $primary2"
    primary_port2=${primary2#*:}
    # 如果 没有这个sleep , 出现 Error: couldn't add user: not master for 3.6
    sleep 3
    $BIN/mongo mongodb://localhost:${primary_port2}/admin --eval 'db.createUser({ user: "admin", pwd: "123456", roles:[ { role: "root", db : "admin" }] })'
}

__initialize_configsvr() {
    echo_with_color "rs.initiate config server"
    $BIN/mongo --port 20000 << eof
    config={_id:"configrs",members: [ { _id:0, host:"$host:20000" },{ _id:1, host:"$host:20001" },{ _id:2, host:"$host:20002" } ]}
    use admin

    //db.createRole({ "role" : "restoreoplog", "privileges" : [ { "resource" : { "anyResource" : true }, "actions" : [ "anyAction" ] } ], "roles" : [ ] })

    //db.createUser({user: "mongouser", pwd: "123456", "roles" : [ { "role" : "dbAdminAnyDatabase", "db" : "admin" }, { "role" : "readWriteAnyDatabase", "db" : "admin" }, { "role" : "backup", "db" : "admin" }, { "role" : "restore", "db" : "admin" }, { "role" : "clusterAdmin", "db" : "admin" }, { "role" : "restoreoplog", "db" : "admin" } ]})  

    rs.initiate(config)
eof

    sleep 3

#    $BIN/mongo mongodb://localhost:${primary_port}/admin --eval 'db.createUser({ user: "admin", pwd: "123456", roles:[ { role: "root", db : "admin" }] })'
}

config_shard() {
    # 在集群启动时应生成 mongouser 用户
    # 在开启keyfile时,貌似创建不了role and user

    __initialize_configsvr
    __initialize_shard1
    __initialize_shard2
}

# 当开启了认证后,必须 先在mongos 那创建一个用户,用它登陆才能addShard
add_shard_to_mongos() {
    echo_with_color "add 2 shards to mongos with admin user ..."
    $BIN/mongo mongodb://admin:123456@$host:30000/admin << eof
    use admin
    // for cmongo, should use token
    db.runCommand( {addShard: "shard1/$host:30001", token: NumberLong("12001087696442048")} )
    db.runCommand( {addShard: "shard2/$host:40001", token: NumberLong("12001087696442048")} )
eof
}

show_shard_stat() {
    $BIN/mongo mongodb://admin:123456@$host:30000/admin << eof
    use admin
    db.runCommand({listShards:1})
    sh.status()
    
    use db1
    db.t.getShardDistribution()
eof
}

shard_db() {
    if [ $# -ne 1 ]; then
        echo "no db name"
        exit 1
    fi
    db=$1
    $BIN/mongo --port 30000 << eof
    use admin
    db.runCommand({enablesharding: "$db"})
    db.runCommand({shardcollection: "$db.t", key: {k: 'hashed'}})
eof
}

run_mongo_commands() {
    echo_with_color "buildinfo ..."
    $BIN/mongo --port 30000 << eof
    db.runCommand({buildinfo:1})
eof
    echo_with_color "listdatabases ..."
    $BIN/mongo --port 30000 << eof
    use admin
    db.runCommand({listdatabases:1})
eof
    #db.runCommand({serverStatus:1}) # very long
    #db.runCommand({ping:1})
}

clear_log() {
    rm -rf shard1/data-* shard2/data-* configrs/data*
    rm -rf *.log
    rm -rf *.diagnostic.data
    mkdir -p shard1/data-30001 shard1/data-30002 shard1/data-30003
    mkdir -p shard2/data-40001 shard2/data-40002 shard2/data-40003
    mkdir -p configrs/data0 configrs/data1 configrs/data2
}

# https://www.jianshu.com/p/f41e35e20e2b
# https://codereview.stackexchange.com/questions/172294/bash-script-to-deploy-a-mongodb-cluster-on-local-machine
start_shard() {
    clear_log

    echo_with_color "starting config server ..."
    $BIN/mongod -f conf/config0.conf
    $BIN/mongod -f conf/config1.conf
    $BIN/mongod -f conf/config2.conf

    echo_with_color "starting shard1 ..."
    $BIN/mongod -f conf/3k1.conf
    $BIN/mongod -f conf/3k2.conf
    $BIN/mongod -f conf/3k3.conf

    echo_with_color "starting shard2 ..."
    $BIN/mongod -f conf/4k1.conf
    $BIN/mongod -f conf/4k2.conf
    $BIN/mongod -f conf/4k3.conf

}

start_mongos() {
    echo_with_color "starting $BIN/mongos server ..."
    if $BIN/mongos --version | grep 'cmongo' > /dev/null; then
        $BIN/mongos -f conf/mongos.conf # 30000
        $BIN/mongos -f conf/mongos2.conf # 40000
    else
        # for original 4.0 without etcdUrl, clusterName
        $BIN/mongos -f conf/mongos-no-clusterName.conf # 30000
        $BIN/mongos -f conf/mongos2-no-clusterName.conf # 40000
    fi

    # 此时localhost 连接可用来创建 user administrator
    echo_with_color "ddd adding admin user against 30000"
    $BIN/mongo --port 30000 << eof
    use admin
    db.createUser({ user: "admin", pwd: "123456", roles:[ { role: "root", db: "admin" } ] })
eof
}

make_sample_data() {
    echo_with_color "write some data to Primary=$primary1 ..."

    $BIN/mongo mongodb://admin:123456@$primary1/admin << eof

    use db1
    for (var i=1; i<=10; i++) {
        db.t.insert({k: i, v: i+1, v2:[i+2,i+3]})
    }

    use db2
    for (var i=1; i<=20; i++) {
        db.t.insert({k: i, v: i+1, v2:[i+2,i+3]})
    }
    db.t.createIndex({ v: 1} , { unique : true})
    
    // map_reduce 例子,统计每个cust id 的总价格
    // https://docs.mongodb.com/v4.0/reference/method/db.collection.mapReduce/
    try {
        db.orders.insertMany([
           { _id: 1, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-01"), price: 25, items: [ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status: "A" },
           { _id: 2, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-08"), price: 70, items: [ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], status: "A" },
           { _id: 3, cust_id: "Busby Bee", ord_date: new Date("2020-03-08"), price: 50, items: [ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status: "A" },
           { _id: 4, cust_id: "Busby Bee", ord_date: new Date("2020-03-18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },
           { _id: 5, cust_id: "Busby Bee", ord_date: new Date("2020-03-19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"},
           { _id: 6, cust_id: "Cam Elot", ord_date: new Date("2020-03-19"), price: 35, items: [ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },
           { _id: 7, cust_id: "Cam Elot", ord_date: new Date("2020-03-20"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },
           { _id: 8, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 75, items: [ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },
           { _id: 9, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 }, { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },
           { _id: 10, cust_id: "Don Quis", ord_date: new Date("2020-03-23"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }
        ])
    } catch (e) {
        print(e)
    }

    var map1 = function() {
        emit(this.cust_id, this.price);
    };
    var reduce1 = function(keyCustId, valuePrices) {
        return Array.sum(valuePrices);
    };
    db.orders.mapReduce(map1, reduce1, { out: "map_reduce_example" })

    // 使用aggregate 实现上述同样功能
    db.orders.aggregate([{ "\$group": { _id:"\$cust_id", value: { "\$sum": "\$price" } } },
        { "\$out": "aggregate_example" }])

    try {
       db.products.insertMany( [
          { item: "card", qty: 15 },
          { item: "envelope", qty: 20 },
          { item: "stamps" , qty: 30 }
       ] );
    } catch (e) {
       print (e);
    }

    // 第二个 _id 13 会失败,剩下的不会再执行(ordered=true时)
    try {
       db.products_use_same__id.insertMany( [
          { _id: 13, item: "envelopes", qty: 60 },
          { _id: 13, item: "stamps", qty: 110 },
          { _id: 14, item: "packing tape", qty: 38 }
       ] );
    } catch (e) {
       print (e);
    }

    // ordered=false时,剩下的doc 也会继续插入
    try {
       db.products_use_ordered_false.insertMany( [
          { _id: 10, item: "large box", qty: 20 },
          { _id: 11, item: "small box", qty: 55 },
          { _id: 11, item: "medium box", qty: 30 },
          { _id: 12, item: "envelope", qty: 100},
          { _id: 13, item: "stamps", qty: 125 },
          { _id: 13, item: "tape", qty: 20},
          { _id: 14, item: "bubble wrap", qty: 30}
       ], { ordered: false } );
    } catch (e) {
       print (e);
    }

eof
}

__create_rs() {
    echo_with_color "creating a local shard1 cluster ..."
    rm -rf shard1/data-*
    rm -rf *.log*
    mkdir -p shard1/data-30001 shard1/data-30002 shard1/data-30003

    if [ $engine = "wiredTiger" ]; then
        #$BIN/mongod -f conf/3k1.conf
        #$BIN/mongod -f conf/3k2.conf
        #$BIN/mongod -f conf/3k3.conf
        # cmongo 4.0 副本集新版本配置中不添加 clusterRole: shardsvr
        $BIN/mongod -f conf/3k1-noshardsvr.conf
        $BIN/mongod -f conf/3k2-noshardsvr.conf
        $BIN/mongod -f conf/3k3-noshardsvr.conf
    elif [ $engine = "rocksdb" ]; then
        $BIN/mongod -f conf/3k1-rocks.conf
        $BIN/mongod -f conf/3k2-rocks.conf
        $BIN/mongod -f conf/3k3-rocks.conf
    fi

    __initialize_shard1

    create_user ${primary1#*:}
    make_sample_data
}

# disable majorityReadConcern
__create_rs_disable_RM() {
    echo_with_color "creating a local shard1 cluster with read majority disabled ..."
    rm -rf shard1/data-*
    rm -rf *.log*
    mkdir -p shard1/data-30001 shard1/data-30002 shard1/data-30003

    if [ $engine = "wiredTiger" ]; then
        $BIN/mongod -f conf/3k1-disable-RM.conf
        $BIN/mongod -f conf/3k2-disable-RM.conf
        $BIN/mongod -f conf/3k3-disable-RM.conf
    fi

    __initialize_shard1

    create_user ${primary1#*:}
    make_sample_data
}

__create_rs_groupCol() {
    echo_with_color "creating a local shard1 cluster with groupCollections enabled ..."
    rm -rf shard1/data-*
    rm -rf *.log*
    mkdir -p shard1/data-30001 shard1/data-30002 shard1/data-30003

    if [ $engine = "wiredTiger" ]; then
        $BIN/mongod -f conf/3k1-groupCol.conf
        $BIN/mongod -f conf/3k2-groupCol.conf
        $BIN/mongod -f conf/3k3-groupCol.conf
    fi

    __initialize_shard1

    create_user ${primary1#*:}
    make_sample_data
}

test_query() {
    $BIN/mongo mongodb://admin:123456@$host:30001/admin << eof
    use db1
    db.t2.aggregate([ {$group: { _id: "$by_user", num_tutorial: { $sum: 1}}} ])
eof
}

__run_rs() {
    echo_with_color "running a local shard1 cluster ..."
    if [ $engine = "wiredTiger" ]; then
        $BIN/mongod -f conf/3k1.conf
        $BIN/mongod -f conf/3k2.conf
        $BIN/mongod -f conf/3k3.conf
    elif [ $engine = "rocksdb" ]; then
        $BIN/mongod -f conf/3k1-rocks.conf
        $BIN/mongod -f conf/3k2-rocks.conf
        $BIN/mongod -f conf/3k3-rocks.conf
    fi
}

__run_rs_groupCol() {
    echo_with_color "running a local shard1 cluster with groupCollections=true ..."
    if [ $engine = "wiredTiger" ]; then
        $BIN/mongod -f conf/3k1-groupCol.conf
        $BIN/mongod -f conf/3k2-groupCol.conf
        $BIN/mongod -f conf/3k3-groupCol.conf
    elif [ $engine = "rocksdb" ]; then
        $BIN/mongod -f conf/3k1-rocks.conf
        $BIN/mongod -f conf/3k2-rocks.conf
        $BIN/mongod -f conf/3k3-rocks.conf
    fi
}

regular_commands() {
    echo
}

stop() {
    #killall $BIN/mongod
    ps aux | grep -v grep | egrep 'mongod -f|mongod --replSet' | awk '{print $2}' | xargs kill
    killall $BIN/mongos
}

# 运行先前已经配置好的集群
run() {
    echo_with_color "starting config server ..."
    $BIN/mongod -f conf/config0.conf
    $BIN/mongod -f conf/config1.conf
    $BIN/mongod -f conf/config2.conf

    echo_with_color "starting shard1 ..."
    $BIN/mongod -f conf/3k1.conf
    $BIN/mongod -f conf/3k2.conf
    $BIN/mongod -f conf/3k3.conf

    echo_with_color "starting shard2 ..."
    $BIN/mongod -f conf/4k1.conf
    $BIN/mongod -f conf/4k2.conf
    $BIN/mongod -f conf/4k3.conf

    echo_with_color "starting mongos server ..."
    $BIN/mongos -f conf/mongos.conf
    $BIN/mongos -f conf/mongos2.conf
}


case $cmd in
    run)
        run
        ;;

    create)
        # order is important !!
        $0 start $BIN
        $0 config $BIN
        $0 startmongos $BIN
        $0 addshard $BIN
        $0 write_data $BIN
        $0 stat $BIN
        ;;

    start)
        start_shard
        ;;

    create_rs)
        __create_rs
        ;;

    create_rs_disable_RM)
        __create_rs_disable_RM
        ;;

    create_rs_groupCol)
        __create_rs_groupCol
        ;;

    run_rs)
        __run_rs
        ;;

    run_rs_groupCol)
        __run_rs_groupCol
        ;;

    run_rs_disable_RM)
        __run_rs_disable_RM
        ;;

    startmongos)
        start_mongos
        ;;

    debug)
        start_debug
        ;;
    simple)
        start_simple
        ;;
    simple2)
        start_simple2
        ;;
    stop)
        stop
        ;;
    rc)
        regular_commands
        ;;
    config)
        config_shard
        ;;
    addshard)
        add_shard_to_mongos
        ;;
    stat)
        show_shard_stat
        ;;
    sharddb)
        shard_db db1
        ;;
    cmd)
        run_mongo_commands
        ;;
    write)
        write_data 50001
        ;;
    write_data)
        write_data 30000
        ;;
    clear_log)
        clear_log
        ;;

    test|t)
        test_query
        ;;
    *)
        echo_with_color "no such sub command"
        ;;

esac
